﻿
Public MustInherit Class _rcclient(Of async_t,
                                      talk_t As {tcpTalk3, New},
                                      pool_t As fixpoint_talkXpool_t(Of talk_t))
    Private talkpool As pool_t = Nothing
    Protected MustOverride Function generateTalkPool(ByVal host As String,
                                                     ByVal port As Int32,
                                                     ByVal holdtimeMs As Int64,
                                                     ByVal livetimeMs As Int64) As pool_t
    Protected MustOverride Function async_talk(ByRef async As async_t,
                                               ByVal talk As talk_t,
                                               ByVal returnTypes() As Type,
                                               ByVal rtns As pointer(Of fromBytes())) As Boolean

    Public Sub New(ByVal host As String, ByVal port As Int32,
                   Optional ByVal holdtimeMs As Int64 = tcpTalk3.defaultHoldTimeMs,
                   Optional ByVal livetimeMs As Int64 = tcpTalk3.defaultLiveTimeMs)
        talkpool = generateTalkPool(host, port, holdtimeMs, livetimeMs)
    End Sub

    Public Property holdtimeMs As Int64
        Get
            Return talkpool.holdtimeMs
        End Get
        Set(ByVal value As Int64)
            talkpool.holdtimeMs = value
        End Set
    End Property

    Public Property livetimeMs As Int64
        Get
            Return talkpool.livetimeMs
        End Get
        Set(ByVal value As Int64)
            talkpool.livetimeMs = value
        End Set
    End Property

    Protected Function talk_finish(ByVal talk_success As Boolean,
                                   ByVal talk As talk_t,
                                   ByVal returnTypes() As Type,
                                   ByVal rtns As pointer(Of fromBytes())) As Boolean
        Dim rtn As Boolean = False
        If talk_success Then
            Dim fb() As fromBytes = Nothing
            If protocol.read(talk.receivedata(), fb, returnTypes, 0) Then
                If Not rtns Is Nothing Then
                    rtns.set(fb)
                End If
                rtn = True
            Else
                raiseError(errorHandle.errorType.user,
                           "cannot get returns for request, ignore.")
                rtn = False
            End If
        Else
            raiseError(errorHandle.errorType.system, "cannot talk with rcserve")
            rtn = False
        End If
        talkpool.release(talk)
        Return rtn
    End Function

    Private Function invokeImpl(ByVal name As String,
                                ByRef action As async_t,
                                ByVal args() As toBytes,
                                ByVal returnTypes() As Type,
                                ByVal rtns As pointer(Of fromBytes()),
                                ByVal talk As talk_t) As Boolean
        If talk.senddata().insert(name) Then
            If args Is Nothing OrElse protocol.write(talk.senddata(), args, isemptyarray(returnTypes)) Then
                Return async_talk(action, talk, returnTypes, rtns)
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    Private Function invokeImpl(ByVal name As String,
                                ByRef action As async_t,
                                ByVal args() As toBytes,
                                ByVal returnTypes() As Type,
                                ByVal rtns As pointer(Of fromBytes())) As Boolean
        Dim talk As talk_t = Nothing
        talk = talkpool.get()
        assert(Not talk Is Nothing)
        If Not invokeImpl(name, action, args, returnTypes, rtns, talk) Then
            talkpool.release(talk)
            Return False
        Else
            Return True
        End If
    End Function

    Public Function invoke(ByVal name As String,
                           ByRef action As async_t,
                           ByVal rtns As pointer(Of fromBytes()),
                           ByVal ParamArray args() As toBytes) As Boolean
        Return invokeImpl(name, action, args, Nothing, rtns)
    End Function

    Public Function invoke(ByVal name As String,
                           ByRef action As async_t,
                           ByVal returnTypes() As Type,
                           ByVal rtns As pointer(Of fromBytes()),
                           ByVal ParamArray args() As toBytes) As Boolean
        Return invokeImpl(name, action, args, returnTypes, rtns)
    End Function
End Class
